from enum import Enum

class ConditionFlow(Enum):
    Break = 0
    Continue = 1

    @staticmethod
    def isBreak(cf):
        return cf is ConditionFlow.Break

    @staticmethod
    def isContinue(cf):
        return cf is ConditionFlow.Continue


class Iterator(object):
    def next(self):
        return None


    #func => lambda(init, item) -> (bool, acc) : True-continue, False-break;
    def try_fold(self, init, func):
        acc = init
        while (item := self.next()) is not None :
            (ok, acc) = func(acc, item)
            if not ok:
                return (ConditionFlow.Break, None)
        
        return (ConditionFlow.Continue, acc)
            
    def try_for_each(self, func):
        return self.try_fold(None, lambda acc, item: func(acc, item))


    # func(init, i) -> acc
    def fold(self, init, func):
        acc = init
        while (item := self.next()) is not None:
            acc = func(acc, item)
        return acc

    def count(self):
        return self.fold(0, lambda acc, _: acc + 1)
    # func(item) -> None
    def for_each(self, func):
        self.fold(None, lambda _, item: func(item))


    """
    def map(self):
        pass

    def filter(self):
        pass
    """

class ListIterator(Iterator):
    def __init__(self, ls):
        self.__list = ls
        self.__index = 0
    
    def next(self):
        if self.__index >= 0 and self.__index < len(self.__list):
            o = self.__list[self.__index] 
            self.__index = self.__index + 1
            return o
        else:
            return None



import unittest

class TestIteartor(unittest.TestCase):
    def test_main(self):
        empty_list = []
        it = ListIterator(empty_list)
        self.assertIsNone(it.next())

        self.assertEqual(0, ListIterator(empty_list).count())

        ls =["world", "hello"]
        it = ListIterator(ls)
        self.assertIsNotNone(it.next())

        self.assertEqual(2, ListIterator(ls).count())


    def test_try_fold(self):
        it = Iterator()
        (ok, ret) = it.try_fold(0, lambda acc, _: (True, acc + 1))
        self.assertEqual(ConditionFlow.Continue, ok)
        self.assertEqual(0, ret)

        ls = [1, 2, 3, 4]
        #count
        (ok, ret) = ListIterator(ls).try_fold(0, lambda acc, _: (True, acc + 1))
        self.assertTrue(ConditionFlow.isContinue(ok))
        self.assertEqual(4, ret)

        # all odd(1,3,...)
        (ok, ret) = ListIterator([1, 3, 5]).try_fold(0, lambda _, item: (item % 2 == 1, item))
        self.assertTrue(ConditionFlow.isContinue(ok))
        self.assertEqual(5, ret)

        # all even(0, 2....)
        (ok, ret) = ListIterator([1, 3, 5]).try_fold(0, lambda _, item: (item % 2 == 0, item))
        self.assertTrue(ConditionFlow.isBreak(ok))
        self.assertIsNone(ret)

        # all even(0, 2....)
        (ok, ret) = ListIterator([0, 2, 4]).try_fold(0, lambda _, item: (item % 2 == 0, item))
        self.assertTrue(ConditionFlow.isContinue(ok))
        self.assertEqual(4, ret)

        ListIterator([0, 2, 4]).for_each(lambda item: print(item))
        

if __name__ == '__main__':
    unittest.main() 
